package com.cskaoyan.javase.object.clone7;

/**
 * @description: clone()方法
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 生物学上的clone，是由物种A的体细胞经过无性繁殖，生成基因型完全一致的后代的过程
 * Java问世时，生物学上clone技术已经风靡全球，所以Java中的clone方法和生物学中的克隆有类似性
 * 所以Java中的克隆就是复制一个和之前对象一模一样但又完全独立的一个新对象
 *
 * 1，克隆后的对象和原先的对象具有相同的成员变量和方法（属性和行为）
 * 2，克隆后的对象是完全独立的
 *
 * Object类当中clone()方法
 *   protected native Object clone() throws CloneNotSupportedException;
 * 注意两个事情：
 *  1.该方法的访问权限：protected
 *  2，该方法是一个本地方法，我们不关心它怎么实现
 *  > clone() 方法对该副本的要求：
 * ​	对于任何对象 x，表达式：
 * ​		1，x.clone() != x 为 true（这一条是必须的）
 *          克隆得到的对象和原先的对象是完全独立
 * ​		2，x.clone().getClass() == x.getClass() 为true
 *          克隆后物种不能变了，对Student对象克隆，得到的仍然是一个Student对象
 * ​		3，x.clone().equals(x) 为true（一般情况下为true，但这并不是必须要满足的要求）
 *          克隆后和原先的对象相等（这个只有在你用成员变量的取值重写equals方法后才成立）
 *
 *  使用克隆方法：
 *  1，注意访问权限
 *  使用clone方法的第一步，是重写该方法访问权限
 *  2,注意CloneNotSupportedException
 *  要想调用某个类的克隆方法，该类必须实现一个接口
 *  Cloneable（支持克隆）
 *  该接口是一个空接口，里面啥都没有
 *  思考：实现一个空接口有啥用？
 *  这种空接口称之为标记接口,可以用instanceof判断一个类是否实现该接口
 *
 *  注意事项:
 *  - 使用clone() 方法创建对象，和new创建对象属于同等级别的Java中创建对象的方式
 *   - clone()方法创建对象是调用native方法，不调用构造方法
 *  克隆是一种独立的创建对象的方式
 *
 * - 返回值类型是一个Object对象，必要的时候要进行强转,不强转无法使用子类独有成员
 *
 *
 *
 *
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s = new Student(18,1000);
        //思考：能不能调用克隆方法？
        //这里不能直接调用，因为不是当前子类创建当前对象
        //我们肯定需要在外部使用clone方法而不是Student类中
        //重写访问权限后可以调用
        Object clone = s.clone();
        System.out.println(clone == s);
        //继续测试他们的成员变量取值
        //必须要做强转
        System.out.println("equals方法结果:"+s.equals(clone));
        Student cloneStu = (Student) clone;
        System.out.println("克隆对象的age:"+cloneStu.age);
        System.out.println("克隆对象的money:"+cloneStu.money);
        System.out.println("原对象的age:"+s.age);
        System.out.println("原对象的money:"+s.money);
        //修改克隆副本中的成员变量取值
        cloneStu.age = 500;
        System.out.println("克隆对象修改后age:"+cloneStu.age);
        System.out.println("原对象修改后的age:"+s.age);

    }
}
class Student implements Cloneable{
    int age;
    double money;

    public Student() {
    }
    public Student(int age, double money) {
        //System.out.println("11111111111111111111");
        this.age = age;
        this.money = money;
    }
    //重写clone()方法访问权限
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return Double.compare(student.money, money) == 0;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        temp = Double.doubleToLongBits(money);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}